
package sc.tool.video;

import java.io.ByteArrayOutputStream;

import sc.tools.ThreadTool;
import sc.tools.ThreadTool.ThreadPram;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.RelativeLayout;


/** 摄像机Surface，对Camera和SurfaceView进行功能逻辑简化封装，方便使用。 
 * (通过该类，可以很方便的实现，视屏图像的实时预览与传输)
 * 
 * 用法：
 * 1、添加CameraSurfaceView至ViewGroup即可展示实时预览图像 
 * 2、重写CallBack_Bitmap逻辑，接收实时预览帧图像
 * ------------ 
 * 
 * 3、若想拍照，调用函数 TakePhoto(); 
 * 4、若想切换摄像头，调用函数 SetFrontCamera(boolean isFront); 
 * 
 * scimence 2020-05-21 23:36 */
public class CameraSurfaceView extends SurfaceView
{
	/** 示例 */
	public static void Example(Activity activity, RelativeLayout layout)
	{
		// 创建预览View
		CameraSurfaceView surView = new CameraSurfaceView(activity, new CallBack_Bitmap()
		{
			@Override
			public void F(Bitmap pic)
			{
				// TODO Auto-generated method stub
				// 2、重写此处逻辑，会实时返回的帧图像，可在此处将图像传输至服务器端
			}
		});
		
		// RelativeLayout layout = (RelativeLayout)activity.findViewById(R.id.layout);
		
		// 1、添加至ViewGroup中，以实时显示预览图像
		layout.addView(surView);
	}
	

	// --------------------------
	
	/** 定义一个Bitmap回调 */
	public interface CallBack_Bitmap
	{
		public void F(Bitmap pic);
	}

	
	// --------------------------
	
	private Activity activity;
	private SurfaceHolder holder;
	private CallBack_Bitmap callBack_frame;	// 用于回调预览帧图像
	
	/** 构造函数，通过CameraSurfaceView展示实时预览图像。(通过callBack_frame，实时返回摄像机帧图像) */
	public CameraSurfaceView(Activity activity, CallBack_Bitmap callBack_frame)
	{
		super(activity);
		
		this.activity = activity;
		this.callBack_frame = callBack_frame;
		
		InitHolder();
	}
	
	/** 通过hoder调用，开启、关闭相机 */
	private void InitHolder()
	{
		holder = getHolder();
		holder.setKeepScreenOn(true);		// 保持屏幕常亮
		//		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		
		holder.addCallback(new SurfaceHolder.Callback()
		{
			@Override
			public void surfaceCreated(SurfaceHolder surfaceHolder)
			{
				StartCamera();
			}
			
			@Override
			public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2)
			{
				Log.i("surfaceChanged", "surfaceChanged");
			}
			
			@Override
			public void surfaceDestroyed(SurfaceHolder surfaceHolder)
			{
				StopCamera();
			}
		});
	}
	
	// --------------------------
	
	/** 在主线程中执行回调处理逻辑 */
	private void RunInMainThread(final CallBack_Bitmap call, final Bitmap pic)
	{
		ThreadTool.RunInMainThread(new ThreadPram()
		{
			@Override
			public void Function()
			{
				if (call != null) call.F(pic);
			}
		});
	}
	
	// --------------------------
	// 以下为camera的操作处理逻辑
	
	private Camera cameraI;											// 定义摄像机
	private int cameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;	// 前置摄像头
	private boolean cameraIsStart = false;							// 记录当前摄像头是否打开
	private int cameraDegree = 0;									// 记录摄像机的旋转角度
	
	/** 使用前置或后置摄像头 */
	public void SetFrontCamera(boolean isFront)
	{
		int cameraId0 = cameraId;
		
		if (isFront)
			cameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
		else cameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
		
		// 选择的摄像头变动时，先关闭摄像头，再重新打开新的
		if (cameraId0 == cameraId)
			return;
		else
		{
			StopCamera();
			StartCamera();
		}
	}
	
	/** 开启摄像机 */
	public void StartCamera()
	{
		// 初始化并打开摄像头
		if (cameraI == null)
		{
			try
			{
				cameraI = Camera.open(cameraId);
				
				Camera.Parameters params = cameraI.getParameters();	//获取Camera参数
				
				params.setPreviewFormat(ImageFormat.NV21); 			// 设置预览图片格式
				params.setPictureFormat(ImageFormat.JPEG); 			// 设置拍照图片格式
				if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
				{
					params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);	// 自动对焦
				}
				cameraI.setParameters(params);
				
				cameraDegree = GetCameraDegree();
				cameraI.setDisplayOrientation(cameraDegree);
				
				cameraI.setPreviewCallback(previewCallback);
				cameraI.setPreviewDisplay(holder);
				cameraI.startPreview();
				
				cameraIsStart = true;
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
				StopCamera();
			}
		}
	}
	
	/** 摄像机预览帧，实时返回逻辑 */
	private Camera.PreviewCallback previewCallback = new Camera.PreviewCallback()
	{
		@Override
		public void onPreviewFrame(final byte[] bytes, Camera camera)
		{
			final Camera.Parameters parameters = camera.getParameters();
			
			// 在主线程中，对帧图像进行处理，不阻塞当前线程（否则会丢帧、帧视屏会有卡顿的情况）
			ThreadTool.RunInSingleThread("preViewFrame", new ThreadPram()
			{
				@Override
				public void Function()
				{
					int imageFormat = parameters.getPreviewFormat();
					int w = parameters.getPreviewSize().width;
					int h = parameters.getPreviewSize().height;
					
					Rect rect = new Rect(0, 0, w, h);
//					Rect rect = new Rect(0, 0, 720, 640);
					YuvImage yuvImg = new YuvImage(bytes, imageFormat, w, h, null);
					try
					{
						ByteArrayOutputStream outputstream = new ByteArrayOutputStream();
						yuvImg.compressToJpeg(rect, 25, outputstream);
						Bitmap pic = BitmapFactory.decodeByteArray(outputstream.toByteArray(), 0, outputstream.size());
						pic = BitmapFormat(pic, -cameraDegree + 90);	// 对预览图像按摄像头角度，进行旋转
						
						// 通过主线程返回帧图像
//						RunInMainThread(callBack_frame, pic);
						if (callBack_frame != null) callBack_frame.F(pic);
					}
					catch (Exception e)
					{}
				}
			});
			
		}
	};
	
	/** 关闭摄像机 */
	public void StopCamera()
	{
		if (cameraI != null)
		{
			cameraIsStart = false;
			
			cameraI.setPreviewCallback(null);
			cameraI.stopPreview();
			cameraI.release();
			cameraI = null;
		}
	}
	
	/** 计算camera的旋转角度 */
	private int GetCameraDegree()
	{
		// 获取界面Activity的旋转角度
		int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
		int degrees = 0;
		if (rotation == Surface.ROTATION_90)
			degrees = 90;
		else if (rotation == Surface.ROTATION_180)
			degrees = 180;
		else if (rotation == Surface.ROTATION_270) degrees = 270;
		
		int degree;
		
		CameraInfo info = new CameraInfo();
		Camera.getCameraInfo(cameraId, info);
		if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
		{
			degree = (info.orientation + degrees) % 360;
			degree = (360 - degree) % 360;
		}
		else
		{
			degree = (info.orientation - degrees + 360) % 360;
		}
		return degree;
//		cameraI.setDisplayOrientation(degree);
	}
	
	/** camera拍照 */
	public void TakePhoto(final CallBack_Bitmap call)
	{
		if (!cameraIsStart) return;	// 若camera未开启，则不可拍照
			
		final PictureCallback jpeg = new PictureCallback()
		{
			@Override
			public void onPictureTaken(final byte[] data, Camera camera)
			{
				ThreadTool.RunInCachedThread(new ThreadPram()
				{
					@Override
					public void Function()
					{
						Bitmap pic = Bytes2Bimap(data);	// 拍摄的数据转化为图像
						RunInMainThread(call, pic);		// 通过主线程返回帧图像
					}
				});
				
				camera.startPreview();
			}
		};
		
		cameraI.takePicture(null, null, jpeg);
	}
	
	/** byte数据转Bitmap */
	private Bitmap Bytes2Bimap(byte[] b)
	{
		if (b == null || b.length == 0)
			return null;
		else return BitmapFactory.decodeByteArray(b, 0, b.length);
	}
	
	/** 对图像进行旋转和缩放，规整化处理（减小图片的大小，以便图像数据快速传输） */
	private Bitmap BitmapFormat(Bitmap bitmap, int degree)
	{
		if (bitmap != null)
		{
			Matrix matrix = new Matrix();
			
			
			// 将图像缩放至480，800 0.75倍
			int width = bitmap.getWidth();
			int height = bitmap.getHeight();
			
			if(width > height)
			{
				width = height;
				height = bitmap.getWidth();
			}
			
			float size1 = 480f / width  * 0.75f;
			float size2 = 800f / height * 0.75f;
			if(size2 > size1) size1 = size2;
			
			matrix.postScale(size1, size1); //长和宽放大缩小的比例
			
			// 旋转图像
			matrix.postRotate(degree);
						
			bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,true);

		}
		
		return bitmap;
		
	}
	
	/** Bitmap旋转任意角度 */
	private Bitmap RotateBitmap(Bitmap bitmap, int degree)
	{
		if (bitmap != null)
		{
			Matrix matrix = new Matrix();
			matrix.postRotate(degree);
			bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,true);
			
			return bitmap;
		}
		return bitmap;
	}
	
	//将Bitmap放大size倍
	private static Bitmap resize(Bitmap bitmap, float size) 
	{
		Matrix matrix = new Matrix(); 
		matrix.postScale(size, size); //长和宽放大缩小的比例
		
		Bitmap resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
		return resizeBmp;
	 }
}
